package com.quectel.taskserver.job.partybuilding;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.partybuilding.PartyPersonMsgBusiness;
import com.quectel.constant.PushConstants;
import com.quectel.constant.core.mobileuser.MobileUserMsgConstants;
import com.quectel.constant.core.partybuilding.PartyBuildingConstants;
import com.quectel.constant.core.partybuilding.PartyBuildingMeetingConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.mobileuser.dto.MobileUserDto;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.core.module.partybuilding.dto.PartyPersonDto;
import com.quectel.core.module.partybuilding.service.PartyPersonService;
import com.quectel.core.module.partybuildingactivity.dto.PartyBuildingActivityDto;
import com.quectel.core.module.partybuildingactivity.dto.PartyBuildingActivityPersonJoinBindingDto;
import com.quectel.core.module.partybuildingactivity.service.PartyBuildingActivityPersonJoinBindingService;
import com.quectel.core.module.partybuildingactivity.service.PartyBuildingActivityService;
import com.quectel.util.common.DateUtils;
import com.quectel.util.kit.PageFetchKit;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.shardingsphere.elasticjob.api.ShardingContext;
import org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 党建活动相关消息推送
 *
 * @author: bob
 * @email: bob.yu@quectel.com
 * @date: 2023-06-12 8:59:00
 */
@Component
public class PartyBuildingActivityMsgPushTask implements SimpleJob {

    private static final Logger LOGGER = LoggerFactory.getLogger(PartyBuildingActivityMsgPushTask.class);
    private static final int TASK_DURATION_MINUTES = 5;

    @DubboReference
    private PartyBuildingActivityService partyBuildingActivityService;
    @DubboReference
    private PartyBuildingActivityPersonJoinBindingService activityPersonJoinBindingService;
    @DubboReference
    private PartyPersonService partyPersonService;
    @DubboReference
    private MobileUserService mobileUserService;

    @Autowired
    private PartyPersonMsgBusiness partyPersonMsgBusiness;

    @Override
    public void execute(ShardingContext shardingContext) {
        generatePartyBuildingMeetingJoinMsg();
        generatePartyBuildingMeetingActivityMsg();
    }

    /**
     * 报名提醒消息
     */
    private void generatePartyBuildingMeetingJoinMsg() {
        LOGGER.info("党建定时推送报名消息，开始执行... 时间 {} 下面各个机器开始抢占执行",  DateUtils.getCurrentDateStr(DateUtils.FormatType.COMMON));

        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getIsPushJoin), SystemConstants.NO);
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getStatus), PartyBuildingMeetingConstants.MeetingStatus.NOT_BEGIN.getStatus());
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getJoinRemindTime), DateUtils.format(new Date(), DateUtils.FormatType.COMMON));


        List<PartyBuildingActivityDto> result = PageFetchKit.fetchAll(r -> partyBuildingActivityService.queryList(r), queryMap);
        if (CollectionUtils.isEmpty(result)){
            LOGGER.error("没有符合条件的活动记录");
            return;
        }


        LOGGER.info("要推送党建活动报名消息的条数{}", result.size());

        for (PartyBuildingActivityDto activityDto: result) {
            Date currentTime = new Date();
            Date joinPushTime = activityDto.getJoinRemindTime();

            List<PartyPersonDto> partyPersonDtoList = new ArrayList<>();
            // 当前时间小于推送时间
            if (DateUtil.between(currentTime, joinPushTime, DateUnit.MINUTE, true) < (TASK_DURATION_MINUTES * 2)) {

                // 查询绑定人员
                List<PartyBuildingActivityPersonJoinBindingDto> bindList
                        = activityPersonJoinBindingService.selectList(activityDto.getId());
                if (CollectionUtils.isEmpty(bindList)){
                    break;
                }

                for (PartyBuildingActivityPersonJoinBindingDto bindingDto : bindList) {
                    PartyPersonDto partyPersonDto = partyPersonService.selectCacheById(bindingDto.getPartyPersonId());
                    if (partyPersonDto!=null){
                        partyPersonDtoList.add(partyPersonDto);
                    }
                }

                if (CollectionUtils.isEmpty(partyPersonDtoList)){
                    return;
                }

                MobileUserMsgConstants.SourceType partyActivityJoinRemind =
                        MobileUserMsgConstants.SourceType.PARTY_ACTIVITY_JOIN_REMIND;
                List<MobileUserDto> sendUserList = getSendUserList(partyPersonDtoList);
                partyPersonMsgBusiness.pushMsg(
                        activityDto.getTenantId(),
                        sendUserList,
                        partyActivityJoinRemind,
                        activityDto.getId(),
                        String.format(PartyBuildingConstants.PUSH_MSG_ACTIVITY_TITLE,
                                MobileUserMsgConstants.SourceType.PARTY_ACTIVITY_JOIN_REMIND.getDefaultTitle()),
                        String.format(PartyBuildingConstants.PUSH_MSG_TEMPLATE,
                                activityDto.getSubject(),
                                DateUtils.format(activityDto.getJoinStartTime(), DateUtils.FormatType.COMMON),
                                DateUtils.format(activityDto.getJoinEndTime(), DateUtils.FormatType.COMMON)
                        ),
                        true,
                        new PushConstants.PushType[]{PushConstants.PushType.WECHAT_OFFICIAL}
                );

                PartyBuildingActivityDto update = new PartyBuildingActivityDto();
                update.setId(activityDto.getId());
                update.setIsPushJoin(SystemConstants.YES);
                partyBuildingActivityService.updateById(update);
            }
        }
        LOGGER.info("党建定时推送报名消息结束");

    }

    /**
     * 签到提醒消息
     */
    private void generatePartyBuildingMeetingActivityMsg() {
        LOGGER.info("党建定时推送签到消息，开始执行... 时间 {} 下面各个机器开始抢占执行",  DateUtils.getCurrentDateStr(DateUtils.FormatType.COMMON));

        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getIsPushActivity), SystemConstants.NO);
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getStatus), PartyBuildingMeetingConstants.MeetingStatus.NOT_BEGIN.getStatus());
        queryMap.put(LambdaUtil.getFieldName(PartyBuildingActivityDto::getActivityRemindTime), DateUtils.format(new Date(), DateUtils.FormatType.COMMON));

        List<PartyBuildingActivityDto> result = PageFetchKit.fetchAll(r -> partyBuildingActivityService.queryList(r), queryMap);
        if (CollectionUtils.isEmpty(result)){
            LOGGER.error("没有符合条件的活动记录");
            return;
        }
        LOGGER.info("要推送党建活动消息的条数{}", result.size());

        for (PartyBuildingActivityDto activityDto: result) {

            Date currentTime = new Date();
            Date activityRemindTime = activityDto.getActivityRemindTime();

            List<PartyPersonDto> partyPersonDtoList = new ArrayList<>();
            if (DateUtil.between(currentTime, activityRemindTime, DateUnit.MINUTE, true) < (TASK_DURATION_MINUTES * 2)) {

                // 查询绑定人员
                List<PartyBuildingActivityPersonJoinBindingDto> bindList
                        = activityPersonJoinBindingService.selectList(activityDto.getId());
                if (CollectionUtils.isEmpty(bindList)){
                    break;
                }

                for (PartyBuildingActivityPersonJoinBindingDto bindingDto : bindList) {
                    PartyPersonDto partyPersonDto = partyPersonService.selectCacheById(bindingDto.getPartyPersonId());
                    if (partyPersonDto!=null){
                        partyPersonDtoList.add(partyPersonDto);
                    }
                }

                if (CollectionUtils.isEmpty(partyPersonDtoList)){
                    return;
                }

                MobileUserMsgConstants.SourceType partyActivityBeginRemind =
                        MobileUserMsgConstants.SourceType.PARTY_ACTIVITY_BEGIN_REMIND;
                List<MobileUserDto> sendUserList = getSendUserList(partyPersonDtoList);
                partyPersonMsgBusiness.pushMsg(
                        activityDto.getTenantId(),
                        sendUserList,
                        partyActivityBeginRemind,
                        activityDto.getId(),
                        String.format(PartyBuildingConstants.PUSH_MSG_ACTIVITY_TITLE,
                                MobileUserMsgConstants.SourceType.PARTY_ACTIVITY_BEGIN_REMIND.getDefaultTitle()),
                        String.format(PartyBuildingConstants.PUSH_MSG_TEMPLATE,
                                activityDto.getSubject(),
                                DateUtils.format(activityDto.getActivityStartTime(), DateUtils.FormatType.COMMON),
                                DateUtils.format(activityDto.getActivityEndTime(), DateUtils.FormatType.COMMON)
                        ),
                        true,
                        new PushConstants.PushType[]{PushConstants.PushType.WECHAT_OFFICIAL}
                );

                PartyBuildingActivityDto update = new PartyBuildingActivityDto();
                update.setId(activityDto.getId());
                update.setIsPushActivity(SystemConstants.YES);
                partyBuildingActivityService.updateById(update);

            }
        }
        LOGGER.info("党建定时推送签到消息结束");

    }

    // 获取发送用户列表,过滤掉没有认证过的人，因为推不出去消息
    private List<MobileUserDto> getSendUserList(List<PartyPersonDto> partyPersonList) {
        return partyPersonList.stream()
                .map(PartyPersonDto::getMobile)
                .map(mobileUserService::selectByMobile)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}
